package org.java.auth.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.authserver.AuthorizationServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;

import java.security.KeyPair;

@Configuration
@EnableAuthorizationServer
@EnableConfigurationProperties(AuthorizationServerProperties.class)//激活某个配置属性的应用
    public class OAuthConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    public PasswordEncoder passwordEncoder;

//  要在SecurityConfig中暴露AuthenticationManager
    @Autowired
    public AuthenticationManager authenticationManager;

    @Autowired
    public AuthorizationServerProperties authorizationServerProperties;
//    配置客户端信息
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        clients
                .inMemory()//在内存中存储客户端信息
                .withClient("api-gateway")//客户端（网关）的ID，用于识别客户端，跟网关上面的客户端名称对应
                .secret(passwordEncoder.encode("123123"))//使用passwordEncoder进行加密，客户端授权的时候，同样要求客户端提供一个密码
                .scopes("all" ) // 授权范围，主要跟客户端要配合一起使用
                .authorizedGrantTypes(  //客户端的支持类型
                        "authorization_code",//获取CODE
                        "password",//基于密码的方式直接访问
                        "token",//基于Token方式访问，基本上都使用这种
                        "implicit")//允许自动确认，并且要严格授权
                .redirectUris("/login/oauth2/code/gateway",
                        "http://127.0.0.1:30001/login/oauth2/code/gateway",
                        "http://api-gateway:8080/login/oauth2/code/gateway",
                        "http://api.fkjava.org/login/oauth2/code/gateway",
                        "https://api.fkjava.org/login/oauth2/code/gateway"
                                )//授权成功以后，重定向到客户端的什么位置，重定向会携带code和state上去

                .autoApprove(true)//自动确认，不会弹出确认界面
        ;
    }

    //配置授权服务
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
//        /oauth/token用于获取code
//        /oauth/authorize 确认授权、授权页面
//        /oauth/refresh_token刷新令牌
//        /oauth/access_token获取访问令牌
//        基于表单的方式进行授权
        security.allowFormAuthenticationForClients();
        security.passwordEncoder(passwordEncoder);
    }

//  配置JWT
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//        /oauth/authorize确认授权页面
        endpoints
                .reuseRefreshTokens(true)//使用刷新令牌
                .authenticationManager(authenticationManager)//认证管理器
                .tokenStore(tokenStore())//令牌存储
                .accessTokenConverter(tokenConverter());//访问令牌转换器
    }
    // 在配置类里面，使用了@Bean注解的方法，只会被调用一次。即使有多次调用，也会被代理掉。
    @Bean
    JwtTokenStore tokenStore() {
        return new JwtTokenStore(tokenConverter());
    }

    @Bean
    JwtAccessTokenConverter tokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();

        KeyStoreKeyFactory keyStoreKeyFactory
                = new KeyStoreKeyFactory(
                // ClassPathResource类相当于就是 classpath:/
                new ClassPathResource(authorizationServerProperties.getJwt().getKeyStore()),
                authorizationServerProperties.getJwt().getKeyStorePassword().toCharArray());
        KeyPair keyPair = keyStoreKeyFactory
                .getKeyPair(authorizationServerProperties.getJwt().getKeyAlias());

        converter.setKeyPair(keyPair);
        return converter;
    }
}
